#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
pipeline.py  (Piper-only)
示例：
  python3 src/pipeline.py --topic "AI 与教育播客的未来" --minutes 3
  python3 src/pipeline.py --topic "AI 播客如何吸引年轻听众" --roles configs/roles_piper.yaml --minutes 3
  python3 src/pipeline.py --topic "AI 与教育播客的未来" --roles configs/roles_piper.yaml --mode deep --minutes 3

说明：
- 仅使用 Piper 进行语音合成。
- 角色/音色、命令模板等在 roles_piper.yaml 里配置。
"""

from dataclasses import dataclass
from datetime import datetime
import argparse
import os
import textwrap
from typing import List, Tuple, Optional

import yaml

from llm_client import LLMClient, Role
from tts_client import TTSClient, Speaker
from audio_utils import concat_wavs_ffmpeg, to_mp3_ffmpeg

# （可选）深度模式
try:
    from rag import retrieve as rag_retrieve
except Exception:
    rag_retrieve = None


def save_text(text: str, out_dir: str, filename: str = "script.txt") -> str:
    os.makedirs(out_dir, exist_ok=True)
    path = os.path.join(out_dir, filename)
    with open(path, "w", encoding="utf-8") as f:
        f.write(text)
    return path


def _abs(p: Optional[str]) -> Optional[str]:
    return os.path.abspath(p) if p else None


def load_roles_yaml(path: str) -> Tuple[List[Role], List[Speaker]]:
    """
    读取 YAML 配置，返回 (roles, speakers)
    仅支持 backend: piper
    字段：
      name, style
      backend: piper
      model_path: xxx.onnx
      config_path: xxx.onnx.json（可选）
      sample_rate: 采样率（默认22050）
      sentence_silence: 句间静音秒（默认0.5）
      tts: { length_scale, noise_scale, noise_w }（可选）
      cmd: 自定义 Piper 命令模板（可选）
    """
    data = yaml.safe_load(open(path, "r", encoding="utf-8"))
    roles_cfg = data.get("roles", [])
    roles: List[Role] = []
    speakers: List[Speaker] = []

    for rc in roles_cfg:
        if rc.get("backend", "piper").lower() != "piper":
            raise ValueError(f"仅支持 backend=piper，发现：{rc.get('backend')}")

        name = rc["name"]
        style = rc.get("style", "")

        roles.append(Role(name=name, style=style))

        speakers.append(
            Speaker(
                name=name,
                backend="piper",
                model_path=_abs(rc.get("model_path")),
                config_path=_abs(rc.get("config_path")),
                sample_rate=int(rc.get("sample_rate", 22050)),
                sentence_silence=float(rc.get("sentence_silence", 0.5)),
                tts_params=rc.get("tts", {}) or {},
                cmd_template=rc.get("cmd"),  # 可选：自定义命令模板
            )
        )

    return roles, speakers


def main():
    parser = argparse.ArgumentParser(description="生成播客脚本并用 Piper 导出音频")
    parser.add_argument("--topic", required=True, help="播客主题")
    parser.add_argument("--minutes", type=int, default=3, help="期望时长（分钟）")
    parser.add_argument("--outdir", default="output", help="输出目录，默认 output/")
    parser.add_argument("--roles", default="configs/roles_piper.yaml", help="角色/音色配置文件")
    parser.add_argument("--mode", default="normal", choices=["normal", "deep"], help="脚本生成模式")
    parser.add_argument("--rounds", type=int, default=None, help="对话轮数（可选）")
    args = parser.parse_args()

    # 1) 角色与音色
    roles, speakers = load_roles_yaml(args.roles)

    os.makedirs(args.outdir, exist_ok=True)

    # 2) 生成脚本（深度模式注入资料）
    client = LLMClient()
    context = None
    if args.mode == "deep" and rag_retrieve is not None:
        context = rag_retrieve(args.topic, top_k=3)
    elif args.mode == "deep" and rag_retrieve is None:
        print("[WARN] 未找到 rag.retrieve，改用 normal 模式。")

    script = client.generate_dialogue(
        topic=args.topic,
        roles=roles,
        minutes=args.minutes,
        rounds=args.rounds,
        mode=args.mode,
        context=context,
    )

    header = textwrap.dedent(f"""\
    # 生成时间：{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
    # 主题：{args.topic}
    # 角色：{", ".join(r.name for r in roles)}
    """)
    script_path = save_text(header + script, args.outdir, "script.txt")

    # 3) TTS（Piper）
    tts_out_dir = os.path.join(args.outdir, "tts")
    tts = TTSClient(speakers=speakers, out_dir=tts_out_dir)
    seg_wavs = tts.synthesize_dialogue(header + script, tts_out_dir)

    # 4) 合并与转码
    final_wav = concat_wavs_ffmpeg(seg_wavs, os.path.join(args.outdir, "podcast.wav"))
    final_mp3 = to_mp3_ffmpeg(final_wav, os.path.join(args.outdir, "podcast.mp3"))

    print("=" * 60)
    print(f"✅ 脚本：{script_path}")
    print(f"✅ 音频：{final_wav} / {final_mp3}")
    print("=" * 60)
    print("脚本预览：")
    print("\n".join((header + script).splitlines()[:12]))


if __name__ == "__main__":
    main()
